package cz.fit.dpo.task1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import cz.fit.dpo.task1.Controller.gameStates;
import cz.fit.dpo.task1.commands.DropCommand;
import cz.fit.dpo.task1.commands.ICommand;
import cz.fit.dpo.task1.commands.LiftCommand;
import cz.fit.dpo.task1.commands.MoveCommand;
import cz.fit.dpo.task1.exceptions.EndOfGameException;
import cz.fit.dpo.task1.exceptions.GamePassedException;
import cz.fit.dpo.task1.utils.Tuple;

public class View implements ICommandProvider {

	public static final String EXIT = "exit";
	public static final String PASS = "pass";
	public static final String HELP = "help";

	private Controller controller = null;

	/**
	 * returns next command entered by user
	 */
	@Override
	public ICommand getNextCommand() throws EndOfGameException,
			GamePassedException {

		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);

		try {
			return parseInput(br.readLine());
		} catch (IOException e) {
			// System.out.println("unknown command - type \"help\" to see available commands");
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Parses the input and returns a command
	 */
	private ICommand parseInput(String input) throws EndOfGameException,
			GamePassedException {
		if (input.startsWith("goto ")) {
			Room r = parseRoom(input.substring(5));
			return new MoveCommand(r);
		} else if (input.startsWith("lift ")) {
			Item i = parseItem(input.substring(5));
			return new LiftCommand(i);
		} else if (input.startsWith("drop ")) {
			Item i = parseItem(input.substring(5));
			return new DropCommand(i);
		} else if (input.equals(EXIT)) {
			throw new EndOfGameException();
		} else if (input.equals(PASS)) {
			throw new GamePassedException();
		} else /* if (input.equals(HELP)) */{
			this.printHelp();
		}
		return null;
	}

	private Item parseItem(String itemName) {
		return this.controller.getGame().findItem(itemName);
	}

	private Room parseRoom(String roomName) {
		return this.controller.getGame().findRoom(roomName);
	}

	@Override
	public void printInputResult(String result) {
		System.out.println(result);
	}

	@Override
	public void printInformation(String info) {
		System.out.println(info);
	}

	/**
	 * Prints a collection of items
	 */
	private void printCollection(String descriptionBeginning,
			String emptyCollection, List<?> collection, String descriptionEnd) {
		int numOfItems = collection.size();
		if (numOfItems > 0) {
			System.out.print(descriptionBeginning);
			int count = 0;
			for (Object item : collection) {
				count++;
				System.out.print(item);
				if (count < numOfItems) {
					if (count + 1 < numOfItems) {
						System.out.print(", ");
					} else {
						System.out.print(" and ");
					}
				}
			}
			System.out.println(descriptionEnd + ".");
		}
	}

	private void printCollection(String descriptionBeginning,
			String emptyCollection, List<?> collection) {
		printCollection(descriptionBeginning, emptyCollection, collection, "");
	}

	/**
	 * Prints the state of the game
	 */
	@Override
	public void printGameState(Game game) {
		System.out.println("");
		System.out.println(" You're in " + game.getPlayer().isInRoom() + ".");
		printCollection(" You possess ", "You don't possess anything", game
				.getPlayer().getOwnedItems());
		printCollection(" There are doors to ", "There are no doors", game
				.getPlayer().isInRoom().getNeighbouringRooms());
		printCollection(" You can see ", "There's nothing around you", game
				.getPlayer().isInRoom().getOwnedItems(), " around you");
		System.out.println(" What do you want to do next?");
		System.out.println("");
	}

	@Override
	public void setController(Controller controller) {
		this.controller = controller;
	}

	/**
	 * Prints help
	 */
	public void printHelp() {
		System.out.println("Commands:");
		System.out.println(HELP + " \t\tprints this help");
		System.out.println("goto <room>\tgo to the neighbor room");
		System.out.println("lift <item>\tpick up the item");
		System.out.println("drop <item>\tdrop the item");
		System.out.println(EXIT + "\tends the game");
		System.out.println(PASS + "\tpass current game");
		System.out.println("");
	}

	@Override
	public void printStartOfGame(Game game) {
		printInformation("Starting game: " + game.getWorld().getName());
		printInformation("Type " + HELP + " to see available commands.");
	}

	@Override
	public void printAvailableGames() {
		System.out.println("Select one of available worlds or type " + EXIT
				+ " to end the game:");
		for (Tuple<World, String> availableWorld : controller
				.getAvailableGames()) {
			System.out.println(availableWorld.getItem2());
		}
	}

	@Override
	public World getWorld() throws EndOfGameException {
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);

		try {
			String line = br.readLine();
			if (line.equals(EXIT)) {
				throw new EndOfGameException();
			} else {
				for (Tuple<World, String> availableWorld : controller
						.getAvailableGames()) {
					if (line.equals(availableWorld.getItem2())) {
						return availableWorld.getItem1();
					}
				}
				printInformation("unknown world");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void printEndOfGame(gameStates gameState) {
		switch (gameState) {
		case PASSED:
			System.out.println("That's a shame, you should play another game!");
			break;
		case WON:
			System.out.println("Congratulations, you have won!!!");
			break;
		default:
			System.out.println("Still playing...");
		}
	}
}